//****************************************************
// Porman Project 
// Filename: CRenderBase.h
// Date: 2011/02/07
// Author: KengYu Lin
// Modify:
//****************************************************
#ifndef _CRENDERBASE_H
#define _CRENDERBASE_H
#include <map>
#include <string>
#include <vector>
#include "CRSDef.h"

namespace Porman
{

namespace RS
{

class CRenderBase
{
public:
    CRenderBase( const std::string& sName, unsigned int uiHash ) : m_sName(sName), m_uiHash(uiHash), m_bFinialize(false) {}
    virtual ~CRenderBase( void ) {}

    PRS_API const std::string& getName( void ) { return m_sName; }
    PRS_API unsigned int getHash( void ) { return m_uiHash; }
    PRS_API void finialize( bool bEnable ) { m_bFinialize = bEnable; }
    PRS_API bool isFinialized( void ) { return m_bFinialize; } 

    virtual void onSwap( void ) = 0; // for Sync region
    virtual void onRender( void ) = 0; // for Redering thread

protected:
    std::string m_sName;
    unsigned int m_uiHash; //Convert from m_sName
    bool m_bFinialize;
};

template<typename T> class CRenderBaseManagerT
{
public:
    typedef std::map<unsigned int, T*> CRenderBaseMap;
    typedef std::vector<unsigned int> CHashVector;

public:
    CRenderBaseManagerT( void ) : m_iUselessObj(0), m_mapTemp(), m_mapContainer(), m_vectUselessHash() {}
    virtual ~CRenderBaseManagerT( void ) 
    {
        deleteAllObj( true );
    }

    virtual T* createObj( const std::string& sName )
    {
        unsigned int uiHashID = _ELFHash( sName );
        T* pObj = _getObj( uiHashID );
        if( !pObj )
        {
            pObj = new T(sName, uiHashID);
            m_mapTemp.insert( CRenderBaseMap::value_type( uiHashID, pObj ) );
        }
        else if( pObj->isFinialized() )
        {
            pObj->finialize( false );
            m_iUselessObj--;
        }
        return pObj;  
    }

    virtual T* getObj( const std::string& sName )
    {
        unsigned int uiHashID = _ELFHash( sName );
        return _getObj( uiHashID );
    }

    virtual bool deleteObj( T** ppObj, bool bImmediate = false )
    {
        T* pObj = _getObj( (*ppObj)->getHash() );
        if( pObj )
        {
            pObj->finialize( true );
            if( !bImmediate )
            {
                m_vectUselessHash.push_back( pObj->getHash() );
                m_iUselessObj++;
            }
            else
            {
                //-------------------
                // Merge first:
                //-------------------
                onMerge();

                //---------------------
                // Delete operation:
                //---------------------
                CRenderBaseMap::iterator ite = m_mapContainer.find( (*ppObj)->getHash() );
                delete ite->second;
                m_mapContainer.erase( ite );
            }

            (*ppObj) = NULL;
            return true;  
        }
        return false;  
    }

    virtual void deleteAllObj( bool bImmediate = false )
    {
        if( bImmediate )
            onMerge();
        else
        {
            CRenderBaseMap::iterator ite;
            CRenderBaseMap::iterator iteEnd = m_mapTemp.end();
            for( ite=m_mapTemp.begin(); ite!=iteEnd; ++ite )
            {
                T* pObj = ite->second;
                pObj->finialize( true );
                m_vectUselessHash.push_back( pObj->getHash() );
                m_iUselessObj++;
            }
        }

        CRenderBaseMap::iterator ite;
        CRenderBaseMap::iterator iteEnd = m_mapContainer.end();
        for( ite=m_mapContainer.begin(); ite!=iteEnd; ++ite )
        {
            T* pObj = ite->second;
            pObj->finialize( true );
            if( !bImmediate )
                m_vectUselessHash.push_back( pObj->getHash() );

            m_iUselessObj++;
        }

        if( bImmediate )
            onClear();
    }

    virtual int getNumObj( void )
    {
        return static_cast<int>( m_mapTemp.size() + m_mapContainer.size() - m_iUselessObj );
    }

    virtual T* getFirst( void )
    {
        CRenderBaseMap::iterator ite = m_mapContainer.begin();
        if( ite != m_mapContainer.end() )
            return ite->second;
        else
            return NULL;
    }

    virtual T* getNext( T* pObj )
    {
        assert(pObj);
        CRenderBaseMap::iterator ite = m_mapContainer.begin();
        if( ite != m_mapContainer.end() )
        {
            while( pObj != ite->second )
                ++ite;

            ++ite;
            if( ite == m_mapContainer.end() )
                return NULL;
            else
                return ite->second;
        }
        return NULL;
    }

    virtual void onMerge( void ) //Merge data into main container!!
    {
        CRenderBaseMap::iterator ite;
        CRenderBaseMap::iterator iteEnd = m_mapTemp.end();
        for( ite=m_mapTemp.begin(); ite!=iteEnd; ++ite )
        {
            m_mapContainer.insert( CRenderBaseMap::value_type( ite->first, ite->second ) );    
        }
        m_mapTemp.clear();
    }

    virtual void onSwap( void ) //Swap data!!
    {
        CRenderBaseMap::iterator ite;
        CRenderBaseMap::iterator iteEnd = m_mapContainer.end();
        for( ite=m_mapContainer.begin(); ite!=iteEnd; ++ite )
        {
            if( !ite->second->isFinialized() )
                ite->second->onSwap();
        }
    }

    virtual void onClear( void ) //Clear useless data!!
    {
        for( size_t i=0; i<m_vectUselessHash.size(); i++ )
        {
            unsigned int uiHash = m_vectUselessHash[i];
            CRenderBaseMap::iterator ite = m_mapContainer.find( uiHash );
            if( ite != m_mapContainer.end() )
            {
                delete ite->second;
                m_mapContainer.erase( ite );
            }
        }
        m_vectUselessHash.clear();
        m_iUselessObj = 0;
    }

protected:
    T* _getObj( unsigned int uiHash )
    {
        CRenderBaseMap::iterator ite = m_mapContainer.find( uiHash );
        if( ite == m_mapContainer.end() )
        {
            ite = m_mapTemp.find( uiHash );
            if( ite == m_mapTemp.end() )
                return NULL;
        }

        if( !ite->second->isFinialized() )
            return ite->second;
        else
            return NULL;    
    }

    unsigned int _ELFHash( const std::string& str )
    { 
        unsigned int hash = 0;
        unsigned int x    = 0;
        for(std::size_t i = 0; i < str.length(); i++)
        {
            hash = (hash << 4) + str[i];
            if((x = hash & 0xF0000000L) != 0)
            {
                hash ^= (x >> 24);
            }
            hash &= ~x;
        }
        return hash;
    }

protected:
    int m_iUselessObj;
    CRenderBaseMap m_mapTemp;
    CRenderBaseMap m_mapContainer;
    CHashVector m_vectUselessHash;
};


}//End namesapce RS

}//End namespace Porman

#endif